import { AdminUser } from './../../schema/admin.schema';
import { Injectable, BadRequestException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import * as bcrypt from 'bcrypt';
import * as jwt from 'jsonwebtoken';
import config from 'src/config/config';
import * as mongoose from 'mongoose';

@Injectable()
export class AdminService {
    constructor(
        @InjectModel('Admin') private readonly adminModel,
        @InjectModel('RoleAccess') private readonly roleAccessModel,
        @InjectModel('Access') private readonly accessModel,
    ) {}
    async find(where = {}, fields = null) {
        try {
            return await this.adminModel.find(where, fields);
        } catch {
            return [];
        }
    }
    async create(userInfo) {
        const { password, username } = userInfo;
        const previousUsers = await this.adminModel.find({ username });
        if (previousUsers.length) throw new BadRequestException('用户名已存在');
        try {
            if (!password) userInfo.password = bcrypt.hashSync(username, 10); //加密级别：10-12;
            return await this.adminModel.create(userInfo);
        } catch {
            return [];
        }
    }
    async update(userInfo) {
        try {
            return await this.adminModel.updateOne({ _id: userInfo._id }, userInfo);
        } catch (error) {
            return null;
        }
    }
    async delete(userInfo) {
        try {
            return await this.adminModel.deleteOne(userInfo);
        } catch (error) {
            return null;
        }
    }
    getModel() {
        return this.adminModel;
    }
    getUserId(req) {
        const authCookie = req.signedCookies[config.authCookieKey];
        if (authCookie) {
            const result = jwt.verify(authCookie, config.jwtSecret);
            const _id = (result as Partial<AdminUser>)._id;
            return _id;
        } else {
            return '';
        }
    }
    async getUser(req) {
        const _id = this.getUserId(req);
        const user = (
            await this.adminModel.aggregate([
                { $match: { _id: new mongoose.Types.ObjectId(_id) } },
                { $lookup: { localField: 'role_id', foreignField: '_id', from: 'role', as: 'role' } },
            ])
        )[0];
        return user;
    }
    async getRole(req) {
        const user = await this.getUser(req);
        const role = user.role[0];
        return role;
    }
    async getMenu(req) {
        const user = await this.getUser(req);
        const role = await this.getRole(req);
        const roleAccessList = await this.roleAccessModel.find({ role_id: role._id });
        const roleAccessListIds = roleAccessList.map((item) => item.access_id);
        const $match: any = { module_id: '0' };
        if (!user.is_super) {
            $match._id = { $in: roleAccessListIds };
        }
        const accessList = await this.accessModel.aggregate([
            { $match },
            {
                $lookup: {
                    localField: '_id',
                    foreignField: 'module_id',
                    from: 'access',
                    as: 'children',
                    pipeline: [{ $match: { type: 2 } }, { $sort: { sort: 1 } }],
                },
            },
        ]);
        return accessList;
    }
    async checkAuth(req) {
        const authCookie = req.signedCookies[config.authCookieKey];
        if (authCookie) {
            const result = jwt.verify(authCookie, config.jwtSecret);
            const _id = (result as Partial<AdminUser>)._id;
            const user = (
                await this.adminModel.aggregate([
                    { $match: { _id: new mongoose.Types.ObjectId(_id) } },
                    { $lookup: { localField: 'role_id', foreignField: '_id', from: 'role', as: 'role' } },
                ])
            )[0];
            if (user.is_super) return true;
            if (!user.role || !user.role.length) throw new BadRequestException('用户未绑定角色');
            const role = user.role[0];
            const roleAccessList = await this.roleAccessModel.aggregate([
                { $match: { role_id: role._id } },
                { $lookup: { from: 'access', localField: 'access_id', foreignField: '_id', as: 'access' } },
            ]);
            const accessList = roleAccessList
                .map((item) => (item.access && item.access.length ? item.access[0] : null))
                .filter((item) => item.status === 1);
            const findResult = accessList.find(
                (item) => item.url === req.originalUrl && req.method.toLowerCase() === item.method.toLowerCase(),
            );
            if (!findResult) {
                return false;
            }
            return true;
        }
        return false;
    }
}
